home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / WINGs / wpopupbutton.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-28  |  18.7 KB  |  782 lines

  1.  
  2.  
  3.  
  4.  
  5. #include "WINGsP.h"
  6.  
  7.  
  8. typedef struct W_PopUpButton {
  9.     W_Class widgetClass;
  10.     WMView *view;
  11.     
  12.     void *clientData;
  13.     WMAction *action;
  14.  
  15.     char *caption;
  16.  
  17.     WMBag *items;
  18.  
  19.     short selectedItemIndex;
  20.     
  21.     short highlightedItem;
  22.     
  23.     WMView *menuView;               /* override redirect popup menu */
  24.  
  25.     WMHandlerID timer;               /* for autoscroll */
  26.  
  27.     /**/
  28.     int scrollStartY;               /* for autoscroll */
  29.     
  30.     struct {
  31.     unsigned int pullsDown:1;
  32.  
  33.     unsigned int configured:1;
  34.     
  35.     unsigned int insideMenu:1;
  36.     
  37.     unsigned int enabled:1;
  38.  
  39.     } flags;
  40. } PopUpButton;
  41.  
  42.  
  43. #define MENU_BLINK_DELAY    60000
  44. #define MENU_BLINK_COUNT    2
  45.  
  46. #define SCROLL_DELAY        10
  47.  
  48.  
  49. #define DEFAULT_WIDTH    60
  50. #define DEFAULT_HEIGHT     20
  51. #define DEFAULT_CAPTION    ""
  52.  
  53.  
  54. static void destroyPopUpButton(PopUpButton *bPtr);
  55. static void paintPopUpButton(PopUpButton *bPtr);
  56.  
  57. static void handleEvents(XEvent *event, void *data);
  58. static void handleActionEvents(XEvent *event, void *data);
  59.  
  60. static void resizeMenu(PopUpButton *bPtr);
  61.  
  62.           
  63. WMPopUpButton*
  64. WMCreatePopUpButton(WMWidget *parent)
  65. {
  66.     PopUpButton *bPtr;
  67.     W_Screen *scr = W_VIEW(parent)->screen;
  68.  
  69.     
  70.     bPtr = wmalloc(sizeof(PopUpButton));
  71.     memset(bPtr, 0, sizeof(PopUpButton));
  72.  
  73.     bPtr->widgetClass = WC_PopUpButton;
  74.     
  75.     bPtr->view = W_CreateView(W_VIEW(parent));
  76.     if (!bPtr->view) {
  77.     wfree(bPtr);
  78.     return NULL;
  79.     }
  80.     bPtr->view->self = bPtr;
  81.     
  82.     WMCreateEventHandler(bPtr->view, ExposureMask|StructureNotifyMask
  83.              |ClientMessageMask, handleEvents, bPtr);
  84.  
  85.  
  86.     W_ResizeView(bPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
  87.     bPtr->caption = wstrdup(DEFAULT_CAPTION);
  88.  
  89.     WMCreateEventHandler(bPtr->view, ButtonPressMask|ButtonReleaseMask,
  90.              handleActionEvents, bPtr);
  91.  
  92.     bPtr->flags.enabled = 1;
  93.     
  94.     bPtr->items = WMCreateBag(4);
  95.  
  96.     bPtr->selectedItemIndex = -1;
  97.  
  98.     bPtr->menuView = W_CreateTopView(scr);
  99.     bPtr->menuView->attribs.override_redirect = True;
  100.     bPtr->menuView->attribFlags |= CWOverrideRedirect;
  101.  
  102.     W_ResizeView(bPtr->menuView, bPtr->view->size.width, 1);
  103.  
  104.     WMCreateEventHandler(bPtr->menuView, ButtonPressMask|ButtonReleaseMask
  105.              |EnterWindowMask|LeaveWindowMask|ButtonMotionMask
  106.              |ExposureMask, handleActionEvents, bPtr);
  107.  
  108.     return bPtr;
  109. }
  110.  
  111.  
  112. void
  113. WMSetPopUpButtonAction(WMPopUpButton *bPtr, WMAction *action, void *clientData)
  114. {
  115.     CHECK_CLASS(bPtr, WC_PopUpButton);
  116.     
  117.     bPtr->action = action;
  118.     
  119.     bPtr->clientData = clientData;
  120. }
  121.  
  122.  
  123. WMMenuItem*
  124. WMAddPopUpButtonItem(WMPopUpButton *bPtr, char *title)
  125. {
  126.     WMMenuItem *item;
  127.     
  128.     CHECK_CLASS(bPtr, WC_PopUpButton);
  129.  
  130.     item = WMCreateMenuItem();
  131.     WMSetMenuItemTitle(item, title);
  132.  
  133.     WMPutInBag(bPtr->items, item);
  134.  
  135.     if (bPtr->menuView && bPtr->menuView->flags.realized)
  136.     resizeMenu(bPtr);
  137.  
  138.     return item;
  139. }
  140.  
  141.  
  142. WMMenuItem*
  143. WMInsertPopUpButtonItem(WMPopUpButton *bPtr, int index, char *title)
  144. {
  145.     WMMenuItem *item;
  146.  
  147.     CHECK_CLASS(bPtr, WC_PopUpButton);
  148.     
  149.     item = WMCreateMenuItem();
  150.     WMSetMenuItemTitle(item, title);
  151.  
  152.     WMInsertInBag(bPtr->items, index, item);
  153.   
  154.     /* if there is an selected item, update it's index to match the new 
  155.      * position */
  156.     if (index < bPtr->selectedItemIndex)
  157.     bPtr->selectedItemIndex++;
  158.     
  159.     if (bPtr->menuView && bPtr->menuView->flags.realized)
  160.     resizeMenu(bPtr);
  161.     
  162.     return item;
  163. }
  164.  
  165.  
  166. void
  167. WMRemovePopUpButtonItem(WMPopUpButton *bPtr, int index)
  168. {
  169.     WMMenuItem *item;
  170.  
  171.     CHECK_CLASS(bPtr, WC_PopUpButton);
  172.  
  173.     wassertr(index >= 0 && index < WMGetBagItemCount(bPtr->items));
  174.     
  175.  
  176.     item = WMGetFromBag(bPtr->items, index);
  177.     WMDeleteFromBag(bPtr->items, index);
  178.  
  179.     WMDestroyMenuItem(item);
  180.  
  181.     if (bPtr->selectedItemIndex >= 0 && !bPtr->flags.pullsDown) {
  182.     if (index < bPtr->selectedItemIndex)
  183.         bPtr->selectedItemIndex--;
  184.     else if (index == bPtr->selectedItemIndex) {
  185.         /* reselect first item if the removed item is the
  186.          * selected one */
  187.         bPtr->selectedItemIndex = 0;
  188.         if (bPtr->view->flags.mapped)
  189.         paintPopUpButton(bPtr);
  190.     }
  191.     }
  192.     
  193.     if (bPtr->menuView && bPtr->menuView->flags.realized)
  194.     resizeMenu(bPtr);
  195. }
  196.  
  197.  
  198. void
  199. WMSetPopUpButtonEnabled(WMPopUpButton *bPtr, Bool flag)
  200. {
  201.     bPtr->flags.enabled = flag;
  202.     if (bPtr->view->flags.mapped)
  203.     paintPopUpButton(bPtr);
  204. }
  205.  
  206.  
  207. Bool
  208. WMGetPopUpButtonEnabled(WMPopUpButton *bPtr)
  209. {
  210.     return bPtr->flags.enabled;
  211. }
  212.  
  213.  
  214. void
  215. WMSetPopUpButtonSelectedItem(WMPopUpButton *bPtr, int index)
  216. {
  217.  
  218.     wassertr(index < WMGetBagItemCount(bPtr->items));
  219.  
  220.     /* if (index >= WMGetBagCount(bPtr->items))
  221.         index = -1;*/
  222.  
  223.     bPtr->selectedItemIndex = index;
  224.     
  225.     if (bPtr->view->flags.mapped)
  226.     paintPopUpButton(bPtr);
  227. }
  228.  
  229. int
  230. WMGetPopUpButtonSelectedItem(WMPopUpButton *bPtr)
  231. {
  232.     if (!bPtr->flags.pullsDown && bPtr->selectedItemIndex < 0)
  233.     return -1;
  234.     else
  235.     return bPtr->selectedItemIndex;
  236. }
  237.  
  238.  
  239. void
  240. WMSetPopUpButtonText(WMPopUpButton *bPtr, char *text)
  241. {
  242.     if (bPtr->caption)
  243.     wfree(bPtr->caption);
  244.     if (text)
  245.     bPtr->caption = wstrdup(text);
  246.     else
  247.     bPtr->caption = NULL;
  248.     if (bPtr->view->flags.realized) {
  249.     if (bPtr->flags.pullsDown || bPtr->selectedItemIndex < 0) {
  250.         paintPopUpButton(bPtr);
  251.     }
  252.     }
  253. }
  254.  
  255.  
  256.  
  257. void 
  258. WMSetPopUpButtonItemEnabled(WMPopUpButton *bPtr, int index, Bool flag)
  259. {
  260.     WMMenuItem *item;
  261.  
  262.     item = WMGetFromBag(bPtr->items, index);
  263.     wassertr(item != NULL);
  264.     
  265.     WMSetMenuItemEnabled(item, flag);
  266. }
  267.  
  268.  
  269. Bool
  270. WMGetPopUpButtonItemEnabled(WMPopUpButton *bPtr, int index)
  271. {
  272.     WMMenuItem *item;
  273.  
  274.     item = WMGetFromBag(bPtr->items, index);
  275.     wassertrv(item != NULL, False);
  276.  
  277.     return WMGetMenuItemEnabled(item);
  278. }
  279.  
  280.  
  281. void
  282. WMSetPopUpButtonPullsDown(WMPopUpButton *bPtr, Bool flag)
  283. {
  284.     bPtr->flags.pullsDown = flag;
  285.     if (flag) {
  286.     bPtr->selectedItemIndex = -1;
  287.     }
  288.  
  289.     if (bPtr->view->flags.mapped)
  290.     paintPopUpButton(bPtr);
  291. }
  292.  
  293.  
  294. int
  295. WMGetPopUpButtonNumberOfItems(WMPopUpButton *bPtr)
  296. {
  297.     return WMGetBagItemCount(bPtr->items);
  298. }
  299.  
  300.  
  301. char*
  302. WMGetPopUpButtonItem(WMPopUpButton *bPtr, int index)
  303. {
  304.     WMMenuItem *item;
  305.  
  306.     if (index >= WMGetBagItemCount(bPtr->items) || index < 0)
  307.     return NULL;
  308.     
  309.     item = WMGetFromBag(bPtr->items, index);
  310.     if (item == NULL)
  311.     return NULL;
  312.  
  313.     return WMGetMenuItemTitle(item);
  314. }
  315.  
  316.  
  317. WMMenuItem*
  318. WMGetPopUpButtonMenuItem(WMPopUpButton *bPtr, int index)
  319. {
  320.     WMMenuItem *item;
  321.  
  322.     item = WMGetFromBag(bPtr->items, index);
  323.  
  324.     return item;
  325. }
  326.  
  327.  
  328.  
  329. static void
  330. paintPopUpButton(PopUpButton *bPtr)
  331. {
  332.     W_Screen *scr = bPtr->view->screen;
  333.     char *caption;
  334.     Pixmap pixmap;
  335.  
  336.     
  337.     if (bPtr->flags.pullsDown) {
  338.     caption = bPtr->caption;
  339.     } else {
  340.     if (bPtr->selectedItemIndex < 0) {
  341.         /* if no item selected, show the caption */
  342.         caption = bPtr->caption;
  343.     } else {
  344.         caption = WMGetPopUpButtonItem(bPtr, bPtr->selectedItemIndex);
  345.     }
  346.     }
  347.  
  348.     pixmap = XCreatePixmap(scr->display, bPtr->view->window, 
  349.                bPtr->view->size.width, bPtr->view->size.height,
  350.                scr->depth);
  351.     XFillRectangle(scr->display, pixmap, WMColorGC(scr->gray), 0, 0,
  352.            bPtr->view->size.width, bPtr->view->size.height);
  353.  
  354.     W_DrawRelief(scr, pixmap, 0, 0, bPtr->view->size.width,
  355.          bPtr->view->size.height, WRRaised);
  356.  
  357.     if (caption) {
  358.     W_PaintText(bPtr->view, pixmap, scr->normalFont, 6, 
  359.             (bPtr->view->size.height-WMFontHeight(scr->normalFont))/2,
  360.             bPtr->view->size.width, WALeft, 
  361.             bPtr->flags.enabled ? WMColorGC(scr->black) : WMColorGC(scr->darkGray),
  362.             False, caption, strlen(caption));
  363.     }
  364.  
  365.     if (bPtr->flags.pullsDown) {
  366.     XCopyArea(scr->display, scr->pullDownIndicator->pixmap, 
  367.           pixmap, scr->copyGC, 0, 0, scr->pullDownIndicator->width,
  368.           scr->pullDownIndicator->height, 
  369.           bPtr->view->size.width-scr->pullDownIndicator->width-4,
  370.           (bPtr->view->size.height-scr->pullDownIndicator->height)/2);
  371.     } else {
  372.     int x, y;
  373.     
  374.     x = bPtr->view->size.width - scr->popUpIndicator->width - 4;
  375.     y = (bPtr->view->size.height-scr->popUpIndicator->height)/2;
  376.     
  377.     XSetClipOrigin(scr->display, scr->clipGC, x, y);
  378.     XSetClipMask(scr->display, scr->clipGC, scr->popUpIndicator->mask);
  379.     XCopyArea(scr->display, scr->popUpIndicator->pixmap, pixmap,
  380.           scr->clipGC, 0, 0, scr->popUpIndicator->width,
  381.           scr->popUpIndicator->height, x, y);
  382.     }
  383.  
  384.     XCopyArea(scr->display, pixmap, bPtr->view->window, scr->copyGC, 0, 0,
  385.           bPtr->view->size.width, bPtr->view->size.height, 0, 0);
  386.     
  387.     XFreePixmap(scr->display, pixmap);
  388. }
  389.  
  390.  
  391.  
  392. static void
  393. handleEvents(XEvent *event, void *data)
  394. {
  395.     PopUpButton *bPtr = (PopUpButton*)data;
  396.  
  397.     CHECK_CLASS(data, WC_PopUpButton);
  398.  
  399.  
  400.     switch (event->type) {
  401.      case Expose:
  402.     if (event->xexpose.count!=0)
  403.         break;
  404.     paintPopUpButton(bPtr);
  405.     break;
  406.     
  407.      case DestroyNotify:
  408.     destroyPopUpButton(bPtr);
  409.     break;
  410.     }
  411. }
  412.  
  413.  
  414.  
  415. static void
  416. paintMenuEntry(PopUpButton *bPtr, int index, int highlight)
  417. {
  418.     W_Screen *scr = bPtr->view->screen;
  419.     int yo;
  420.     int width, height, itemHeight, itemCount;
  421.     char *title;
  422.  
  423.     itemCount = WMGetBagItemCount(bPtr->items);
  424.     if (index < 0 || index >= itemCount)
  425.         return;
  426.  
  427.     itemHeight = bPtr->view->size.height;
  428.     width = bPtr->view->size.width;
  429.     height = itemHeight * itemCount;
  430.     yo = (itemHeight - WMFontHeight(scr->normalFont))/2;
  431.  
  432.     if (!highlight) {
  433.     XClearArea(scr->display, bPtr->menuView->window, 0, index*itemHeight,
  434.            width, itemHeight, False);
  435.     return;
  436.     } else if (index < 0 && bPtr->flags.pullsDown) {
  437.     return;
  438.     }
  439.     
  440.     XFillRectangle(scr->display, bPtr->menuView->window, WMColorGC(scr->white),
  441.            1, index*itemHeight+1, width-3, itemHeight-3);
  442.     
  443.     title = WMGetPopUpButtonItem(bPtr, index);
  444.  
  445.     W_DrawRelief(scr, bPtr->menuView->window, 0, index*itemHeight, 
  446.          width, itemHeight, WRRaised);
  447.  
  448.     W_PaintText(bPtr->menuView, bPtr->menuView->window, scr->normalFont,  6, 
  449.         index*itemHeight + yo, width, WALeft, WMColorGC(scr->black), 
  450.         False, title, strlen(title));
  451.  
  452.     if (!bPtr->flags.pullsDown && index == bPtr->selectedItemIndex) {
  453.     XCopyArea(scr->display, scr->popUpIndicator->pixmap, 
  454.           bPtr->menuView->window, scr->copyGC, 0, 0, 
  455.           scr->popUpIndicator->width, scr->popUpIndicator->height,
  456.           width-scr->popUpIndicator->width-4, 
  457.           index*itemHeight+(itemHeight-scr->popUpIndicator->height)/2);
  458.     }
  459. }
  460.  
  461.  
  462. Pixmap
  463. makeMenuPixmap(PopUpButton *bPtr)
  464. {
  465.     Pixmap pixmap;
  466.     W_Screen *scr = bPtr->view->screen;
  467.     WMMenuItem *item;
  468.     WMBagIterator iter;
  469.     int yo, i;
  470.     int width, height, itemHeight;
  471.     
  472.     itemHeight = bPtr->view->size.height;
  473.     width = bPtr->view->size.width;
  474.     height = itemHeight * WMGetBagItemCount(bPtr->items);
  475.     yo = (itemHeight - WMFontHeight(scr->normalFont))/2;
  476.     
  477.     pixmap = XCreatePixmap(scr->display, bPtr->view->window, width, height, 
  478.                scr->depth);
  479.     
  480.     XFillRectangle(scr->display, pixmap, WMColorGC(scr->gray), 0, 0,
  481.            width, height);
  482.  
  483.     i = 0;
  484.     WM_ITERATE_BAG(bPtr->items, item, iter) {
  485.     GC gc;
  486.     char *text;
  487.  
  488.     text = WMGetMenuItemTitle(item);
  489.  
  490.     W_DrawRelief(scr, pixmap, 0, i*itemHeight, width, itemHeight, 
  491.              WRRaised);
  492.  
  493.         if (!WMGetMenuItemEnabled(item))
  494.         gc = WMColorGC(scr->darkGray);
  495.     else
  496.         gc = WMColorGC(scr->black);
  497.  
  498.     W_PaintText(bPtr->menuView, pixmap, scr->normalFont,  6, 
  499.             i*itemHeight + yo, width, WALeft, gc, False,
  500.             text, strlen(text));
  501.     
  502.     if (!bPtr->flags.pullsDown && i == bPtr->selectedItemIndex) {
  503.         XCopyArea(scr->display, scr->popUpIndicator->pixmap, pixmap, 
  504.               scr->copyGC, 0, 0, scr->popUpIndicator->width,
  505.               scr->popUpIndicator->height, 
  506.               width-scr->popUpIndicator->width-4,
  507.               i*itemHeight+(itemHeight-scr->popUpIndicator->height)/2);
  508.     }
  509.     
  510.     i++;
  511.     }
  512.     
  513.     return pixmap;
  514. }
  515.  
  516.  
  517. static void
  518. resizeMenu(PopUpButton *bPtr)
  519. {
  520.     int height;
  521.     
  522.     height = WMGetBagItemCount(bPtr->items) * bPtr->view->size.height;
  523.     if (height > 0)
  524.     W_ResizeView(bPtr->menuView, bPtr->view->size.width, height);
  525. }
  526.  
  527.  
  528. static void
  529. popUpMenu(PopUpButton *bPtr)
  530. {
  531.     W_Screen *scr = bPtr->view->screen;
  532.     Window dummyW;
  533.     int x, y;
  534.  
  535.     if (!bPtr->menuView->flags.realized) {
  536.     W_RealizeView(bPtr->menuView);
  537.     resizeMenu(bPtr);
  538.     }
  539.     
  540.     if (WMGetBagItemCount(bPtr->items) < 1)
  541.     return;
  542.     
  543.     XTranslateCoordinates(scr->display, bPtr->view->window, scr->rootWin,
  544.               0, 0, &x, &y, &dummyW);
  545.  
  546.     if (bPtr->flags.pullsDown) {
  547.     y += bPtr->view->size.height;
  548.     } else {
  549.     y -= bPtr->view->size.height*bPtr->selectedItemIndex;
  550.     }
  551.     W_MoveView(bPtr->menuView, x, y);
  552.     
  553.     XSetWindowBackgroundPixmap(scr->display, bPtr->menuView->window,
  554.                    makeMenuPixmap(bPtr));
  555.     XClearWindow(scr->display, bPtr->menuView->window);
  556.     
  557.     W_MapView(bPtr->menuView);
  558.     
  559.     bPtr->highlightedItem = 0;
  560.     if (!bPtr->flags.pullsDown && bPtr->selectedItemIndex < 0)
  561.     paintMenuEntry(bPtr, bPtr->selectedItemIndex, True);
  562. }
  563.  
  564.  
  565. static void
  566. popDownMenu(PopUpButton *bPtr)
  567. {
  568.     W_UnmapView(bPtr->menuView);
  569.     
  570.     /* free the background pixmap used to draw the menu contents */
  571.     XSetWindowBackgroundPixmap(bPtr->view->screen->display, 
  572.                    bPtr->menuView->window, None);
  573. }
  574.  
  575.  
  576. static void
  577. autoScroll(void *data)
  578. {
  579.     PopUpButton *bPtr = (PopUpButton*)data;
  580.     int scrHeight = WMWidgetScreen(bPtr)->rootView->size.height;
  581.     int repeat = 0;
  582.     int dy = 0;
  583.  
  584.  
  585.     if (bPtr->scrollStartY >= scrHeight-1
  586.     && bPtr->menuView->pos.y+bPtr->menuView->size.height >= scrHeight-1) {
  587.     repeat = 1;
  588.  
  589.     if (bPtr->menuView->pos.y+bPtr->menuView->size.height-5 
  590.         <= scrHeight - 1) {
  591.         dy = scrHeight - 1
  592.         - (bPtr->menuView->pos.y+bPtr->menuView->size.height);
  593.     } else
  594.         dy = -5;
  595.  
  596.     } else if (bPtr->scrollStartY <= 1 && bPtr->menuView->pos.y < 1) {
  597.     repeat = 1;
  598.  
  599.     if (bPtr->menuView->pos.y+5 > 1) 
  600.         dy = 1 - bPtr->menuView->pos.y;
  601.     else
  602.         dy = 5;
  603.     }
  604.  
  605.     if (repeat) {
  606.     int oldItem;
  607.  
  608.     W_MoveView(bPtr->menuView, bPtr->menuView->pos.x, 
  609.            bPtr->menuView->pos.y + dy);
  610.  
  611.     oldItem = bPtr->highlightedItem;
  612.     bPtr->highlightedItem = (bPtr->scrollStartY - bPtr->menuView->pos.y)
  613.         / bPtr->view->size.height;
  614.  
  615.     if (oldItem!=bPtr->highlightedItem) {
  616.             WMMenuItem *item;
  617.  
  618.         paintMenuEntry(bPtr, oldItem, False);
  619.  
  620.             if (bPtr->highlightedItem >= 0 &&
  621.                 bPtr->highlightedItem < WMGetBagItemCount(bPtr->items)) {
  622.                 item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
  623.                 paintMenuEntry(bPtr, bPtr->highlightedItem,
  624.                                WMGetMenuItemEnabled(item));
  625.             } else {
  626.                 bPtr->highlightedItem = -1;
  627.             }
  628.     }
  629.  
  630.     bPtr->timer = WMAddTimerHandler(SCROLL_DELAY, autoScroll, bPtr);
  631.     } else {
  632.     bPtr->timer = NULL;
  633.     }
  634. }
  635.  
  636.  
  637. static void
  638. handleActionEvents(XEvent *event, void *data)
  639. {
  640.     PopUpButton *bPtr = (PopUpButton*)data;
  641.     int oldItem;
  642.     int scrHeight = WMWidgetScreen(bPtr)->rootView->size.height;
  643.  
  644.     CHECK_CLASS(data, WC_PopUpButton);
  645.  
  646.     if (WMGetBagItemCount(bPtr->items) < 1)
  647.     return;
  648.     
  649.     switch (event->type) {
  650.     /* called for menuView */
  651.      case Expose:
  652.     paintMenuEntry(bPtr, bPtr->highlightedItem, True);
  653.     break;
  654.  
  655.      case LeaveNotify:
  656.     bPtr->flags.insideMenu = 0;
  657.     if (bPtr->menuView->flags.mapped)
  658.         paintMenuEntry(bPtr, bPtr->highlightedItem, False);
  659.     bPtr->highlightedItem = -1;
  660.     break;
  661.     
  662.      case EnterNotify:
  663.     bPtr->flags.insideMenu = 1;
  664.     break;
  665.  
  666.      case MotionNotify:
  667.     if (bPtr->flags.insideMenu) {
  668.         oldItem = bPtr->highlightedItem;
  669.         bPtr->highlightedItem = event->xmotion.y / bPtr->view->size.height;
  670.         if (oldItem!=bPtr->highlightedItem) {
  671.         WMMenuItem *item;
  672.         
  673.         paintMenuEntry(bPtr, oldItem, False);
  674.                 if (bPtr->highlightedItem >= 0 &&
  675.                     bPtr->highlightedItem < WMGetBagItemCount(bPtr->items)) {
  676.                     item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
  677.                     paintMenuEntry(bPtr, bPtr->highlightedItem,
  678.                                    WMGetMenuItemEnabled(item));
  679.                 } else {
  680.                     bPtr->highlightedItem = -1;
  681.                 }
  682.  
  683.         }
  684.  
  685.         if (event->xmotion.y_root >= scrHeight-1
  686.         || event->xmotion.y_root <= 1) {
  687.         bPtr->scrollStartY = event->xmotion.y_root;
  688.         if (!bPtr->timer)
  689.             autoScroll(bPtr);
  690.         } else if (bPtr->timer) {
  691.         WMDeleteTimerHandler(bPtr->timer);
  692.         bPtr->timer = NULL;
  693.         }
  694.     }
  695.     break;
  696.     
  697.     /* called for bPtr->view */
  698.      case ButtonPress:
  699.     if (!bPtr->flags.enabled)
  700.         break;
  701.  
  702.     popUpMenu(bPtr);
  703.     if (!bPtr->flags.pullsDown) {
  704.         bPtr->highlightedItem = bPtr->selectedItemIndex;
  705.         bPtr->flags.insideMenu = 1;
  706.     } else {
  707.         bPtr->highlightedItem = -1;
  708.         bPtr->flags.insideMenu = 0;
  709.     }
  710.     XGrabPointer(bPtr->view->screen->display, bPtr->menuView->window,
  711.              False, ButtonReleaseMask|ButtonMotionMask|EnterWindowMask
  712.              |LeaveWindowMask, GrabModeAsync, GrabModeAsync, 
  713.              None, None, CurrentTime);
  714.     break;
  715.  
  716.      case ButtonRelease:
  717.     XUngrabPointer(bPtr->view->screen->display, event->xbutton.time);
  718.     if (!bPtr->flags.pullsDown)
  719.         popDownMenu(bPtr);
  720.  
  721.     if (bPtr->timer) {
  722.         WMDeleteTimerHandler(bPtr->timer);
  723.         bPtr->timer = NULL;
  724.     }
  725.  
  726.     if (bPtr->flags.insideMenu && bPtr->highlightedItem>=0) {    
  727.         WMMenuItem *item;
  728.         
  729.         item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
  730.         
  731.             if (WMGetMenuItemEnabled(item)) {
  732.         int i;
  733.                 WMSetPopUpButtonSelectedItem(bPtr, bPtr->highlightedItem);
  734.  
  735.         if (bPtr->flags.pullsDown) {
  736.             for (i=0; i<MENU_BLINK_COUNT; i++) {
  737.             paintMenuEntry(bPtr, bPtr->highlightedItem, False);
  738.             XSync(bPtr->view->screen->display, 0);
  739.             wusleep(MENU_BLINK_DELAY);
  740.             paintMenuEntry(bPtr, bPtr->highlightedItem, True);
  741.             XSync(bPtr->view->screen->display, 0);
  742.             wusleep(MENU_BLINK_DELAY);
  743.             }
  744.         }
  745.         paintMenuEntry(bPtr, bPtr->highlightedItem, False);
  746.         popDownMenu(bPtr);
  747.                 if (bPtr->action)
  748.                     (*bPtr->action)(bPtr, bPtr->clientData);
  749.             }
  750.     }
  751.     if (bPtr->menuView->flags.mapped)
  752.         popDownMenu(bPtr);
  753.     break;
  754.     }    
  755. }
  756.  
  757.  
  758.  
  759. static void
  760. destroyPopUpButton(PopUpButton *bPtr)
  761. {
  762.     WMMenuItem *item;
  763.     WMBagIterator i;
  764.  
  765.     if (bPtr->timer) {
  766.     WMDeleteTimerHandler(bPtr->timer);
  767.     }
  768.  
  769.     WM_ITERATE_BAG(bPtr->items, item, i) {
  770.     WMDestroyMenuItem(item);
  771.     }
  772.     WMFreeBag(bPtr->items);
  773.  
  774.     if (bPtr->caption)
  775.     wfree(bPtr->caption);
  776.  
  777.     /* have to destroy explicitly because the popup is a toplevel */
  778.     W_DestroyView(bPtr->menuView);
  779.  
  780.     wfree(bPtr);
  781. }
  782.